home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / Modes / fortranMode.tcl < prev    next >
Encoding:
Text File  |  2000-12-07  |  21.1 KB  |  672 lines

  1. #=============================================================================
  2. # Fortran mode definition and support procs
  3. #
  4. # Features:
  5. # 1.  Keyword colorization (slightly customizable)
  6. # 2.  Fortran-sensitive shift right/left preserve columns 1-6
  7. # 3.  Auto-indentation
  8. # 4.  Line-breaking with Ctl-Opt-J (a la emacs)
  9. # 5.  Subroutine indexing
  10. # 6.  Cmd-double-click subroutine and include-file lookup
  11. # 7.  Customizable comment and continuation characters
  12. #
  13. #------------------------------------------------------------------------------
  14. # Author: Tom Pollard <pollard@chem.columbia.edu>
  15. #
  16. # To Do:  work around grep failure for Unix-format tag files
  17. #
  18. #  8/97 - Updated for new system code.
  19. #  4/97 - Coloring bug fixed.
  20. #  1/96 - Fort::MarkFile no longer marks F90 "end subroutine ..." statements
  21. #         more F90 keywords (will they never cease?)
  22. #  1/96 - user-selectable comment and continuation characters
  23. #         complete F90 keyword set (Thomas Bewley <bewley@rayleigh.stanford.edu>) 
  24. #         F90 functions and comparison operators optionally colorized ( " " )
  25. #         more complete set of C preprocessor commands colorized
  26. #         fixed case-sensitivity problem in line-indent routines
  27. #  1/96 - minor Fort::DblClick bug fix
  28. # 12/95 - more complete keyword set for F90 and HPF (from Tom Scavo)
  29. # 12/95 - cpp keyword colorization (George Nurser <g.nurser@soc.soton.ac.uk>)
  30. #         cmd-dbl-click supports cpp #include now
  31. # 11/95 - added FortBreakLine
  32. #         fixed case-sensitivity bug
  33. # 10/95 - fixed Cmd-Dbl-Click handler to deal w/ new(?) tag file format and
  34. #            improve performance (fortFindSub)
  35. #  9/95 - fixed getFortPrev bug with numbered lines
  36. #       - shiftLeft/Right revert to normal behavior on ill-formatted lines
  37. #  8/95 - auto-indentation is finally speedy and robust
  38. #  5/95 - added Cmd-Dbl-Click handler
  39. #       - added auto-indentation
  40. # 12/94 - fixed funcExpr, Fort::MarkFile search expressions
  41. #       - changed comment character from 'C' to 'c' (should be case-insensitive!)
  42. #       - added 'include' keyword
  43. #       - added FortShiftRight and FortShiftLeft procs
  44. #------------------------------------------------------------------------------
  45.  
  46.  
  47. #================================================================================
  48. alpha::mode Fort 1.0.2 dummyFort \
  49.   {*.f *.inc *.INC *.fcm *.for *.FOR *.f9 *.f90 *.hpf } {electricTab} {
  50.     set unixMode(fortran) {Fort}
  51. } help {
  52.     Fortran Mode provides keyword coloring, subrouting marking and
  53.     indexing, Fortran sensitive shifting of blocks of code preservering
  54.     columns 1-6, automatic code indentation.  Line breaks are inserted
  55.     with ctrl-opt-J. Supports cmd-dbl-click for jumping to subroutines
  56.     and opening of include files.  Comment characters can be set in
  57.     Preferences (F12).
  58.  
  59.     Click on this "FORTRAN Example.f" link for an example syntax file.
  60. }
  61.  
  62. proc dummyFort {} {}
  63.  
  64. newPref f sortedIsDefault    {0} Fort
  65. newPref f wordWrap        {0} Fort
  66. newPref v funcExpr    {^[^cC*!][ \t]*(subroutine|[ \ta-z*0-9]*function|entry).*$} Fort
  67. newPref f autoMark        {0} Fort
  68.  
  69. newPref    v continueChar    {$} Fort
  70. newPref    v commentChar    {c} Fort shadowFort
  71. newPref    f colorFuncs    {0} Fort shadowFort
  72. newPref    f colorOpers    {0} Fort shadowFort
  73.  
  74. newPref f indentComment    {0} Fort
  75. newPref v markTag        {{}} Fort
  76.  
  77. #=============================================================================
  78. # Colorize Fortran keywords
  79. #
  80. proc fortColorKeywords {{color blue} {comment red} {specialChars black}} {
  81.     global FortmodeVars
  82.     
  83.     set FortKeywords { 
  84.     allocatable allocate assign backspace block call character close common 
  85.     complex contains continue cycle data deallocate dimension do double else 
  86.     elseif end enddo endfile endif entry equivalence exit external extrinsic 
  87.     forall format function goto if implicit include inquire integer intent 
  88.     interface intrinsic logical module namelist nullify open optional 
  89.     parameter pause pointer precision print private program public pure read 
  90.     real recursive return rewind save sequence stop subroutine target then 
  91.     use where while write assignment case default elsewhere endfile go none 
  92.     operator procedure select to type
  93.     }
  94.     
  95.     if {$specialChars != "black"} {
  96.     regModeKeywords -e $FortmodeVars(commentChar) -c $comment -k $color Fort $FortKeywords  -i {=}  -i {*}  -i {/}  -i {+}  -i {-}  -i {,}  -i {(} -i {)} -I $specialChars
  97.     } else {
  98.     regModeKeywords -e $FortmodeVars(commentChar) -c $comment -k $color Fort $FortKeywords  
  99.     }
  100.     unset FortKeywords
  101.  
  102. #=============================================================================
  103. # Colorize selected C preprocessor keywords
  104. #
  105. proc fortColorCPP {{color green}} {
  106.     set CPPKeywords  {
  107.     #if #endif #include #else #define #undef #ifdef #ifndef
  108.     }
  109.     regModeKeywords -a  -k $color Fort $CPPKeywords
  110.     unset CPPKeywords
  111. }
  112.  
  113.  
  114. #=========================================================================
  115. # Colorize Fortran operators
  116. #
  117. proc fortColorOpers {{color green}} {
  118.     set FortOperators {
  119.     eq ne lt le gt ge not and or eqv neqv true false
  120.     }
  121.     regModeKeywords -a -k $color Fort $FortOperators
  122.     unset FortOperators
  123. }
  124.  
  125. #=========================================================================
  126. # Colorize Fortran function keywords
  127. #
  128. proc fortColorFuncs {{color green}} {
  129.     # Fortran bit functions
  130.     #
  131.     set BitKeywords {
  132.     bit_size btest iand ibclr ibits ibset ieor ior ishft ishftc mvbits not
  133.     }
  134.     regModeKeywords -a -k $color Fort $BitKeywords
  135.     unset BitKeywords
  136.     
  137.     # Fortran intrinsic functions
  138.     #
  139.     set IntrinsicKeywords {
  140.     abs acos aimag asin atan atan2 conjg cos cosh dble dim dprod exp ichar 
  141.     len lge lgt lle llt log log10 max min mod sign sin sinh sqrt tan tanh 
  142.     iabs dabs cabs dacos dint dnint dasin datan datan2 dcos ccos dcosh idim 
  143.     ddim dexp cexp ifix idint alog ddlog clog alog10 dlog10 max0 amax0 max1 
  144.     amax1 dmax1 min0 amin0 min1 amin1 dmin1 amod dmod idnint float sngl 
  145.     isign dsign dsin csin dsinh dsqrt csqrt dtan dtanh aint anint char cmplx 
  146.     index int nint achar adjustl adjustr all allocated any associated 
  147.     bit_size btest ceiling count cshift date_and_time digits dot_product 
  148.     eoshift epsilon exponent floor fraction huge iachar iand ibclr ibits 
  149.     ibset ieor ior ishft ishftc kind lbound len_trim logical matmul 
  150.     maxexponent maxloc maxval merge minexponent minloc minval modulo mvbits 
  151.     nearest not pack precision present product radix random_number 
  152.     random_seed range repeat reshape rrspacing scale scan selected_int_kind 
  153.     selected_real_kind set_exponent shape size spacing spread sum 
  154.     system_clock tiny transfer transpose trim ubound unpack verify
  155.     }
  156.     regModeKeywords -a -k $color Fort $IntrinsicKeywords
  157.     unset IntrinsicKeywords    
  158. }
  159.  
  160. fortColorKeywords blue red magenta
  161. fortColorCPP green
  162. if {$FortmodeVars(colorFuncs)} {
  163.     fortColorFuncs green
  164. }
  165. if {$FortmodeVars(colorOpers)} {
  166.     fortColorOpers green
  167. }
  168. #=============================================================================
  169. # Special Fortran keybindings
  170. #
  171. Bind '\[' <c>  FortShiftLeft Fort
  172. Bind '\[' <co> FortShiftLeftSpace Fort
  173. Bind '\]' <c>  FortShiftRight Fort
  174. Bind '\]' <co> FortShiftRightSpace Fort
  175.  
  176. Bind 'j'  <zo> FortBreakLine Fort
  177.  
  178. #=============================================================================
  179. # Update colorization when Fortran mode variables are changed
  180. #
  181. proc shadowFort {name2} {
  182.     global HOME FortmodeVars
  183.     switch -- $name2 {
  184.     "colorFuncs"    {
  185.         if {$FortmodeVars(colorFuncs)} {
  186.         fortColorFuncs green
  187.         } else {
  188.         fortColorFuncs black
  189.         }
  190.     }
  191.     "colorOpers"    {
  192.         if {$FortmodeVars(colorOpers)} {
  193.         fortColorOpers green
  194.         } else {
  195.         fortColorOpers black
  196.         }
  197.     }
  198.     "commentChar" {    
  199.         fortColorKeywords blue red magenta
  200.     }
  201.     default {
  202.         return
  203.     }
  204.     }
  205. }
  206.  
  207. #=============================================================================
  208. #
  209. proc Fort::MarkFile {} {
  210.     global FortmodeVars
  211.     set tag [quote::Regfind $FortmodeVars(markTag)]
  212.     
  213.     set pat0 {^.*(subroutine|.*function|entry|program).*$}
  214.     set pat1 {^[^cC*!]([ \ta-z*0-9]*)(subroutine|.*function|entry|program)[ \t]+([a-z0-9_]+)}
  215.     set end [maxPos]
  216.     set pos [minPos]
  217.     while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $pat1 $pos} mtch]} {
  218.     regexp -nocase $pat1 [eval getText $mtch] allofit valtyp subtyp name
  219.     set start [lineStart [lindex $mtch 0]]
  220.     set next [nextLineStart $start]
  221.     set pos $next
  222.     if {! [regexp -nocase "end" $valtyp mtch]} {
  223.         set inds([lineStart $start]) $name
  224.     }
  225.     
  226.     }
  227.     
  228.     set pat2 "^(c+${tag})\[ \t\]*(\[^\n\r\]*\[^ \t\])\[^ \t\]*\$"
  229.     set pos [minPos]
  230.     while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $pat2 $pos} mtch]} {
  231.     regexp -nocase $pat2 [eval getText $mtch] allofit cc comment
  232.     regsub -all {[\/\(\)]} $comment {} comment
  233.     set start [lindex $mtch 0]
  234.     set end [nextLineStart $start]
  235.     set pos $end
  236.     set inds([lineStart $start]) $comment
  237.     }
  238.     
  239.     if {[info exists inds]} {
  240.     foreach f [lsort -integer [array names inds]] {
  241.         set next [nextLineStart $f ]
  242.         setNamedMark $inds($f) $f $f $f
  243.     }
  244.     }
  245. }
  246.  
  247. #================================================================================
  248. # Block shift left and right for Fortran mode (preserves cols 1-6)
  249. #================================================================================
  250.  
  251. proc FortShiftLeft {} {
  252.     global shiftChar
  253.     doFortShiftLeft "\t"
  254.     
  255. }
  256. proc FortShiftLeftSpace {} {
  257.     global shiftChar
  258.     doFortShiftLeft " "
  259. }
  260.  
  261. proc doFortShiftLeft {shiftChar} {
  262.     set start [lineStart [getPos]]
  263.     set end [nextLineStart [pos::math [selEnd] - 1]]
  264.     if {[pos::compare $start >= $end]} {set end [nextLineStart $start]}
  265.     
  266.     set text [split [getText $start [pos::math $end - 1]] "\r"]
  267.     
  268.     set textout ""
  269.     
  270.     set pat {^([cC]|[ 0-9][ 0-9][ 0-9][ 0-9][ 0-9].| *[0-9]*\t)(.*)$}
  271.     foreach line $text {
  272.     if {[regexp $pat $line mtch pref body]} {
  273.         if {[string index $body 0] == $shiftChar} {
  274.         lappend textout $pref[string range $body 1 end]
  275.         } else {
  276.         lappend textout $line
  277.         }
  278.         
  279.     } elseif {[string index $line 0] == $shiftChar} {
  280.         lappend textout [string range $line 1 end]
  281.         
  282.     } else {
  283.         lappend textout $line
  284.     }
  285.     }
  286.     
  287.     set text [join $textout "\r"]    
  288.     replaceText $start [pos::math $end - 1] $text
  289.     select $start [pos::math $start + 1 + [string length $text]]
  290. }
  291.  
  292. proc FortShiftRight {} {
  293.     global shiftChar
  294.     doFortShiftRight "\t"
  295.     
  296. }
  297. proc FortShiftRightSpace {} {
  298.     global shiftChar
  299.     doFortShiftRight " "
  300. }
  301.  
  302. proc doFortShiftRight {shiftChar} {
  303.     set start [lineStart [getPos]]
  304.     set end [nextLineStart [pos::math [selEnd] - 1]]
  305.     if {[pos::compare $start >= $end]} {set end [nextLineStart $start]}
  306.     
  307.     set text [split [getText $start [pos::math $end - 1]] "\r"]
  308.     
  309.     set textout ""
  310.     
  311.     set pat {^([cC]|[ 0-9][ 0-9][ 0-9][ 0-9][ 0-9].| *[0-9]*\t)(.*)$}
  312.     foreach line $text {
  313.         if {[regexp $pat $line mtch pref body]} {
  314.             lappend textout $pref$shiftChar$body
  315.         } else {
  316.             lappend textout $shiftChar$line
  317.         }
  318.     }
  319.     
  320.     set text [join $textout "\r"]    
  321.     replaceText $start [pos::math $end - 1] $text
  322.     select $start [pos::math $start + 1 + [string length $text]]
  323. }
  324.  
  325. proc FortBreakLine {} {
  326.     global FortmodeVars
  327.     set pos [getPos]
  328.     set line [getText [lineStart $pos] [pos::math [nextLineStart $pos] - 1]]
  329.     if {[regexp {^[cC*!]} $line char]} {
  330.     insertText "\n$char "
  331.     } else {
  332.     set char $FortmodeVars(continueChar)
  333.     insertText "\n     $char"
  334.     }
  335.     FortindentLine
  336. }
  337.  
  338. #=============================================================================
  339. # Cmd-double-clicking opens include files, jumps to subroutine definitions,
  340. # and follows tags.
  341. #
  342. proc Fort::DblClick {from to} {
  343.     global tagFile
  344.     set pat1 {^[^cC*!][ \ta-z*0-9]*(subroutine|.*function|entry)[ \t]+}
  345.     set incPat {^[^cC*!][ \t]*include[ \t]*['"]([^'"]+)['"]}
  346.     
  347.     # First check whether an 'include' was clicked
  348.     set line [getText [lineStart $from] [pos::math [nextLineStart $to] - 1]]
  349.     if {[regexp -nocase $incPat $line allofit fname]} {
  350.     set path [absolutePath $fname]
  351.     if {[catch {file::openQuietly $path}]} { 
  352.         message "include file \'$fname\' not found in source folder"
  353.     }
  354.     return
  355.     }
  356.     
  357.     select $from $to
  358.     set text [getSelect]
  359.     
  360.     # First check current file for subroutine definition,...
  361.     if {![catch {fortFindSub $text} mtch]} { 
  362.     regexp -nocase $pat1 [eval getText $mtch] allofit subtyp name
  363.     placeBookmark
  364.     display [lindex $mtch 0]
  365.     #         eval select $mtch
  366.     message "press <Ctl .> to return to original cursor position"
  367.     
  368.     # ...then check tags file.
  369.     } else {
  370.     message "Searching tags file..."
  371.     set lines [grep "^$text'" $tagFile]
  372.     if {[regexp {'(.*)'} $lines dummy fname]} { 
  373.         placeBookmark
  374.         file::openQuietly $fname
  375.         set inds [fortFindSub $text]
  376.         #             set inds [search -s -f 1 -r 1 -i 1 "$pat1$text" 0]
  377.         display [lindex $inds 0]
  378.         #             eval select $inds
  379.         message "press <Ctl .> to return to original cursor position"
  380.     }
  381.     }
  382. }
  383.  
  384. # Speedy search for a Fortran subroutine.  Performance is dramatically 
  385. # improved by scanning for the name alone first, rather than running 
  386. # complicated regexp search on the entire file.
  387. #
  388. proc fortFindSub {name} {
  389.     set pat1 {^[^cC*!][ \ta-z*0-9]*(subroutine|.*function|entry)[ \t]+}
  390.     set pos [minPos]
  391.     while {![catch {search -s -f 1 -r 0 -m 0 -i 1 $name $pos} mtch]} {
  392.     set beg [lineStart [lindex $mtch 0]]
  393.     set end [pos::math [nextLineStart [lindex $mtch 1]] -1]
  394.     set line [getText $beg $end]
  395.     if {[regexp  -nocase $pat1$name $line allofit subtyp name]} {
  396.         return $mtch 
  397.     } else {
  398.         set pos [lindex $mtch 1]
  399.     }
  400.     }
  401.     error "Subroutine \"$name\" not found"
  402. }
  403.  
  404. #=============================================================================
  405. # Fortan auto-indentation
  406. #
  407. # Logic:
  408. #    0.    Identify previous line
  409. #            a) ignore comments and continuation lines
  410. #            b) if current line is a CONTINUE that matches a DO, use the
  411. #                first corresponding DO as the previous line
  412. #
  413. #    1.    Find leading whitespace for previous line
  414. #
  415. #    2.    Increase whitespace if previous line starts a block, i.e.,
  416. #            a) DO loop
  417. #            b) IF ... THEN 
  418. #            c) ELSE
  419. #
  420. #    3.    Decrease whitespace if current line ends a block, i.e.,
  421. #            a) ELSE || ENDIF || END IF || ENDDO || END DO
  422. #            b) <linenum> CONTINUE matching a preceding DO
  423. #
  424. #        or if previous line ends a DO loop on an executable statement, i.e.,
  425. #            c) <linenum> (not CONTINUE) matching a preceding DO
  426. #
  427. ####################################################################################
  428. # Fortan auto-indentation
  429. #
  430. proc Fort::indentLine {} {    
  431.     set bol [lineStart [getPos]]
  432.     set eol [pos::math [nextLineStart $bol] - 1]
  433.     Fortindent $bol $eol
  434. }
  435.  
  436. proc Fort::indentRegion {} {    
  437.     Fortindent [getPos] [selEnd]
  438. }
  439.  
  440. ####################################################################################
  441. # Fortan auto-indentation of a specified region
  442. #
  443. proc Fortindent {pos0 pos1} {
  444.     global fortDooz fortPrevLine fortTop msg
  445.     global FortmodeVars
  446.     
  447.     set tag [quote::Regfind $FortmodeVars(markTag)]
  448.     set doComment $FortmodeVars(indentComment)
  449.     
  450.     # Define regexps
  451.     set subPat {^[^cC*!][ \ta-z*0-9]*(subroutine|.*function|entry|program)[ \t]+([a-z0-9_]+)}
  452.     set bolPat {^[^cC*!\n\r][ \t]*[^ \t\n\r][^\r\n]*$}
  453.     set mtPat {^[ \t]*$}
  454.     set tab "    "
  455.     
  456.     set contPat {^     ([^ \t\n\r])[^\r\n]*$}
  457.     set lnumPat {^([ \t]*)([0-9]*)([ \t]*)(.*)$}
  458.     set comPat "^(\[cC*!\]+(${tag})?)(\[ \t\]*)(.*)\$"
  459.     set doPat {^[^cC*!\n\r][ \t]*do[ \t]+}
  460.     set tailPat {[^\r\n]*$}
  461.     
  462.     set bobPat {^(if[^\n\r]*then|else|do)}
  463.     set eobPat {^(end[ \t]*if|end[ \t]*do|else)}
  464.     set enddoPat {^(end[ \t]*do|continue)}
  465.     
  466.     #     set fortTop [fortSubTop $pos0]
  467.     set fortTop -1
  468.     
  469.     catch {unset fortDooz}
  470.     set fortPrevLine ""
  471.     
  472.     # Loop over region line by line
  473.     set from [lindex [posToRowCol $pos0] 0]
  474.     set to [lindex [posToRowCol $pos1] 0]
  475.     
  476.     while {$from <= $to} {        
  477.     set msg "Indenting line $from"
  478.     message $msg
  479.     set bol [lineStart [rowColToPos $from 0]]
  480.     set eol [pos::math [nextLineStart $bol] - 1]
  481.     set thisLine [getText $bol $eol]
  482.     goto $bol
  483.     
  484.     # Check whether we're entering a new routine
  485.     #
  486.     if {[regexp $subPat $thisLine allofit subType subName]} {
  487.         # alertnote "entering subr: \/$subName\/"
  488.         set fortTop $bol
  489.         catch {unset fortDooz}
  490.     } 
  491.     
  492.     # Is the current line a comment line...
  493.     #        
  494.     if {[regexp $comPat $thisLine allofit cc tag pre body]} {
  495.         if {$FortmodeVars(indentComment) > 0} {
  496.         set body [string trimright $body]
  497.         # alertnote "comment line: \/$pre\/$body\/"
  498.         set lwhite "$cc     "
  499.         
  500.         replaceText $bol $eol $lwhite$body
  501.         }
  502.         
  503.         # ... or a line of code (possibly empty)?
  504.         #    
  505.     } elseif {[regexp $lnumPat $thisLine allofit pre lnum post body]} {
  506.         set body [string trimright $body]
  507.         # alertnote "line: \/$pre\/$lnum\/$post\/$body\/"
  508.         
  509.         # is it a continuation line?
  510.         #
  511.         if {(![regexp "\t" $pre]) && ([string length $pre] == 5)} {
  512.         set cont [string index $lnum$post$body 0]
  513.         set body [string trimleft [string range $lnum$post$body 1 end]]
  514.         } else {
  515.         set cont {}
  516.         }
  517.         # alertnote "cont: \/$cont\/"
  518.         
  519.         # get whitespace for preceding line
  520.         set enddo [getFortPrev $bol $lnum]
  521.         set lwhite [getFortLwhite $bol]
  522.         
  523.         # if this line ends a block, decrease the whitespace
  524.         if {[regexp $eobPat $body] || ($enddo && [regexp -nocase $enddoPat $body])} {
  525.         set lwlen [expr [string length $lwhite] - 4]
  526.         set lwhite [string range $lwhite 0 $lwlen]
  527.         } 
  528.         
  529.         if {[string length $lnum]} {
  530.         if {[string index $lwhite 0] != $tab} {
  531.             set lwhite [string range $lwhite [expr [string length $lnum] +1] end]
  532.         }
  533.         set lnum " $lnum"
  534.         }
  535.         # alertnote "lwhite: \/$lwhite\/ len: [string length $lwhite]"
  536.         # message "$msg : replacing text      "
  537.         
  538.         if {[string length $cont]} {
  539.         replaceText $bol $eol "     $cont$lwhite$body"    
  540.         } else {
  541.         replaceText $bol $eol $lnum$lwhite$body
  542.         if {[string length $body] > 0} {
  543.             set fortPrevLine $lnum$lwhite$body
  544.         }
  545.         }
  546.     } else {
  547.         # message "$msg : Couldn't parse line         "
  548.     }
  549.     
  550.     # message "$msg : Done                "
  551.     incr from
  552.     }
  553. }
  554.  
  555. proc getFortLwhite {bol} {
  556.     global fortDooz fortPrevLine fortTop msg
  557.     # Define regexps
  558.     set tab "    "
  559.     set lnumPat {^([ \t]*)([0-9]*)([ \t]*)(.*)$}
  560.     set doPat {^[^cC*!\n\r][ \t]*do[ \t]+}
  561.     set bobPat {^(if[^\n\r]*then|else|do)}
  562.     set enddoPat {^(end[ \t]*do|continue)}
  563.     
  564.     if {[regexp $lnumPat $fortPrevLine allofit pre0 lnum0 post0 body0]} {
  565.     # alertnote "prevLine: \/$pre0\/$lnum0\/$post0\/$body0\/"
  566.     
  567.     if {[string length $lnum0]} {
  568.         if {[string index $post0 0] == $tab} {
  569.         set lwhite $post0
  570.         } else {
  571.         regsub -all {[0-9]} $pre0$lnum0$post0 { } lwhite
  572.         }
  573.     } else {
  574.         set lwhite $pre0
  575.     }
  576.     # alertnote "lwhite: \/$lwhite\/ len: [string length $lwhite]"
  577.     # message "$msg : got lwhite (initial)"
  578.     
  579.     # if there's a line number and it's not a CONTINUE or ENDDO, 
  580.     # then check for a matching DO statement and adjust 
  581.     # indentation if found
  582.     #
  583.     if {[string length $lnum0] && ![regexp -nocase $enddoPat $body0]} {
  584.         if {[getFortPrev [lineStart [pos::math $bol - 1]] $lnum0]} {
  585.         set lwlen [expr [string length $lwhite] - 4]
  586.         set lwhite [string range $lwhite 0 $lwlen]
  587.         
  588.         }
  589.     }
  590.     
  591.     # If the preceeding line begins a block (IF-THEN, DO, or ELSE),
  592.     # then increase the whitespace
  593.     #    
  594.     if {[regexp -nocase $bobPat $body0]} {
  595.         set lwhite "$lwhite   "
  596.         
  597.         if {[regexp -nocase "$doPat\(\[0-9\]+\)" $body0 mtch donum]} {
  598.         set eol [pos::math [nextLineStart $bol] - 1]
  599.         set fortDooz($donum) [getText $bol $eol]
  600.         }
  601.     }
  602.     # message "$msg : got lwhite (final)  "
  603.     }
  604.     return "$lwhite"
  605. }
  606.  
  607. proc getFortPrev {bol lnum} {        
  608.     global fortDooz fortPrevLine fortTop msg
  609.     # Define regexps
  610.     set doPat {^[^cC*!\n\r][ \t]*do[ \t]+}
  611.     set bolPat {^[^cC*!\n\r][ \t]*[^ \t\n\r][^\r\n]*$}
  612.     set contPat {^     ([^ \t\n\r])[^\r\n]*$}
  613.     
  614.     # if there's a line number, check for a matching DO statement ...
  615.     if {[string length $lnum]} {
  616.     if {[lsearch [array names fortDooz] $lnum] >= 0} {
  617.         set fortPrevLine $fortDooz($lnum)
  618.         return 1
  619.     } else {
  620.         if {$fortTop < 0} {
  621.         set fortTop [fortSubTop $bol]
  622.         }
  623.         if {![catch {search -s -f 0 -r 1 -i 1 -l $fortTop $doPat$lnum [expr $bol -1]} dolst]} {
  624.         set fortPrevLine [eval getText $dolst]
  625.         set fortDooz($lnum) $fortPrevLine
  626.         # alertnote "doLine0: \/$fortPrevLine\/"
  627.         return 1
  628.         }
  629.     }
  630.     }
  631.     
  632.     # ... otherwise find the first preceding non-comment, non-continuation line
  633.     if {[string length $fortPrevLine] == 0} {
  634.     if {[catch {
  635.         set lst [search -s -f 0 -r 1 -i 1 -s $bolPat [expr $bol-1]]
  636.         set fortPrevLine [eval getText $lst]
  637.         while {[regexp -nocase $contPat $fortPrevLine]} {
  638.         set lst [search -s -f 0 -r 1 -i 1 $bolPat [expr [lindex $lst 0] - 1]]
  639.         set fortPrevLine [eval getText $lst]
  640.         }
  641.     }]} {
  642.         # if search fails, we're at the top of a file, so reset indentation
  643.         set fortPrevLine "      continue"
  644.     }
  645.     }
  646.     
  647.     # alertnote "prevLine: \/$fortPrevLine\/"
  648.     # message "$msg : got prevLine"
  649.     return 0
  650. }
  651.  
  652. # Find the beginning of the current subroutine
  653. #
  654. proc fortSubTop {{pos 0}} {
  655.     if {$pos == 0} {
  656.     set pos [lineStart [getPos]]
  657.     }
  658.     set subPat {^[^cC*!][ \ta-z*0-9]*(subroutine|.*function|entry|program)[ \t]+([a-z0-9_]+)}
  659.     
  660.     if {![catch {search -s -f 0 -r 1 -m 0 -i 1 $subPat $pos} sublst]} {
  661.     # set subLine [eval getText $sublst]
  662.     # alertnote "subLine: \/$subLine\/"
  663.     return [lindex $sublst 0]
  664.     } else {
  665.     return [minPos]
  666.     } 
  667. }
  668.  
  669.  
  670.  
  671.